//*************************************************************************************************
// SSAUTOI.H
//
// Internal definitions for the SourceSafe OLE automation interface.
//*************************************************************************************************
#ifndef __SSAUTOI_H__
#define __SSAUTOI_H__
#include "ssauto.h"							// SourceSafe automation definitions.
#include "TFSComApi.h"						// The COM API for the TFS object model
#include "olehelp.h"						// OLE(COM) utilities.
#include "locks.h"							// Some mutex locking classes.
#include "Trace.h"

#define INITPUBLICMETHOD(piid)	SSAutoEnter sSSAutoEnter(piid);

#ifdef _DEBUG
#define DEBUG_STMT(x) x
#else
#define DEBUG_STMT(x)
#endif

#define UnNULLStr(s) ((s) != NULL ? (s) : L"NULL")
//void Trace(char *text, ...);
//void Trace(LPWSTR text, ...);
//void TraceStr(char *text);
//void CloseTrace();

// Some global variables.
extern LONG giObj;							// # of OLE objects running in DLL
extern LONG giLock;							// Count of locks on DLL.
#ifdef _DEBUG
extern LONG giVSSItem;
extern LONG giVSSDatabase;
#endif
extern CCritLock gsMutex;

// forward declares
struct RIGHTS;

// Internal functions.
HRESULT FillErrorInfo(LPCTSTR szMsg, DWORD dwHelpContext);

// Routines to filter errors from back to the caller.
HRESULT HRError(HRESULT hr);
HRESULT SSError(int iStat, ...);

// Macro to save typing for declaring the IDispatch methods.
#define DECLARE_AUTOMATION() \
    STDMETHODIMP GetTypeInfoCount(UINT FAR *pctinfo); \
    STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo); \
    STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, \
								LCID lcid, DISPID *rgdispid); \
    STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, \
								DISPPARAMS *pdispparams, VARIANT *pvarResult, \
								EXCEPINFO *pexcepinfo, UINT *puArgErr);

// Macro to save typing for implementing the IDispatch methods.
#define IMPLEMENT_AUTOMATION(cls) \
	HRESULT cls::GetTypeInfoCount(UINT *piCount) \
	{ \
		Trace::Write("Enter IDispatch::GetTypeInfoCount"); \
		*piCount = 1; \
		return S_OK; \
	} \
	HRESULT cls::GetTypeInfo(UINT iInfo, LCID lcid, ITypeInfo **ppITypeInfo) \
	{ \
		Trace::Write("Enter IDispatch::GetTypeInfo"); \
		return HRError(m_TI.GetTypeInfo(iInfo, lcid, ppITypeInfo)); \
	} \
	HRESULT cls::GetIDsOfNames(REFIID sIID, OLECHAR **pszNames, UINT iNames, LCID lcid, DISPID *piDispID) \
	{ \
		Trace::Write("Enter IDispatch::GetIDsOfNames"); \
		return HRError(m_TI.GetIDsOfNames(sIID, pszNames, iNames, lcid, piDispID)); \
	} \
	HRESULT cls::Invoke(DISPID iDispID, REFIID sIID, LCID lcid, USHORT iFlags, DISPPARAMS *psParams, \
					VARIANT *psResult, EXCEPINFO *psExcep, UINT *piArgErr) \
	{ \
		Trace::Write("Enter IDispatch::Invoke"); \
		return HRError(m_TI.Invoke((IDispatch *)this, iDispID, sIID, lcid, iFlags, \
				psParams, psResult, psExcep, piArgErr)); \
	}

// Macro to save typing for validating impersonation.
#define VERIFY_IMPERSONATION \
{ \
	if (gfImpersonate) \
	{ \
		HRESULT hr = ::CoImpersonateClient(); \
		if (FAILED(hr)) \
		{ \
			Trace::Write("VERIFY_IMPERSONATION FAILED"); \
			return hr; \
		} \
	} \
}

//*************************************************************************************************
// This class is used to automatic construction/destruction on entry and exit of every public
// function.
//*************************************************************************************************
class SSAutoEnter
{
	static int	m_iEntered;					// In the automation API?
	const IID	*m_psIID;					// Interface we are in.

public:
	SSAutoEnter(const IID *psIID);
	~SSAutoEnter();
};

//*************************************************************************************************
// Basic interface implementation used to implement ISupportErrorInfo in all of the COM classes.
//*************************************************************************************************
class CImpISupportErrorInfo : public ISupportErrorInfo
{
	DefineIRef();							// Interface reference count.
	IUnknown	*m_pObj;					// Object we belong to.

public:
	CImpISupportErrorInfo(IUnknown	*pObj) : // Object we belong to.
		InitIRef()
		m_pObj(pObj)
	{
		Trace::Write("Enter CImpISupportErrorInfo");
	}

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj)
	{ 
		Trace::Write("Enter CImpISupportErrorInfo::QueryInterface");
		return m_pObj->QueryInterface(riid, ppvObj); 
	}
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CImpISupportErrorInfo::AddRef");
		IncIRef();
		return m_pObj->AddRef();
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CImpISupportErrorInfo::Release");
		DecIRef();
		return m_pObj->Release();
	}

	// ISupportErrorInfo methods.
	STDMETHODIMP InterfaceSupportsErrorInfo(REFIID riid)
	{
		Trace::Write("Enter CImpISupportErrorInfo::InterfaceSupportsErrorInfo");
		return S_OK;
	}
};

class CVSSItem;

//*************************************************************************************************
//*************************************************************************************************
class CImpIVSSItem : public IVSSItem
{
	DefineIRef();							// Interface reference count.

	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CVSSItem		*m_pObj;				// Back pointer to the object.

public:
	CImpIVSSItem(CVSSItem *pObj) :
		InitIRef()
		m_pObj(pObj)
	{
		Trace::Write("Enter CImpIVSSItem");
	}

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSItem methods */
    STDMETHODIMP get_Spec(BSTR *pSpec);
    STDMETHODIMP get_Binary(VARIANT_BOOL *pbBinary);
    STDMETHODIMP put_Binary(VARIANT_BOOL bBinary);
    STDMETHODIMP get_Deleted(VARIANT_BOOL *pbDeleted);
    STDMETHODIMP put_Deleted(VARIANT_BOOL bDeleted);
    STDMETHODIMP get_Type(int *piType);
    STDMETHODIMP get_LocalSpec(BSTR *pLocal);
    STDMETHODIMP put_LocalSpec(BSTR Local);
    STDMETHODIMP get_Name(BSTR *pName);
    STDMETHODIMP put_Name(BSTR Name);
    STDMETHODIMP get_Parent(IVSSItem **ppIParent);
    STDMETHODIMP get_VersionNumber(long *piVersion);
    STDMETHODIMP get_IsPinned(VARIANT_BOOL *pbBinary);
    STDMETHODIMP get_Size(LONG *piSize);
    STDMETHODIMP get_Items(VARIANT_BOOL IncludeDeleted, IVSSItems **ppIItems);
    STDMETHODIMP Get(BSTR *Local, long iFlags);
    STDMETHODIMP Checkout(BSTR Comment, BSTR Local, long iFlags);
    STDMETHODIMP Checkin(BSTR Comment, BSTR Local, long iFlags);
    STDMETHODIMP UndoCheckout(BSTR Local, long iFlags);
    STDMETHODIMP get_IsCheckedOut(long *piStatus);
    STDMETHODIMP get_Checkouts(IVSSCheckouts **ppIChkouts);
    STDMETHODIMP get_IsDifferent(BSTR Local, VARIANT_BOOL *pbDifferent);
    STDMETHODIMP Add(BSTR Local,BSTR Comment, long iFlags, IVSSItem **ppIItem);
    STDMETHODIMP NewSubproject(BSTR Name, BSTR Comment, IVSSItem **ppIItem);
    STDMETHODIMP Share(IVSSItem *pIItem, BSTR Comment, long iFlags);
    STDMETHODIMP Destroy();
    STDMETHODIMP Move(IVSSItem *pINewParent);
    STDMETHODIMP Label(BSTR Label, BSTR Comment);
    STDMETHODIMP get_Versions(long iFlags, IVSSVersions **ppIVersions);
    STDMETHODIMP get_Version(VARIANT Version, IVSSItem **ppIItem);

	STDMETHODIMP get_Links(IVSSItems **ppIItems);
	STDMETHODIMP Branch(BSTR Comment, long iFlags, IVSSItem **ppIItem);

	STDMETHODIMP get_Child(BSTR Spec, VARIANT_BOOL Deleted, IVSSItem **ppIVSSItem);
	STDMETHODIMP get_VSSVersion(IVSSVersion **ppIVersion);
    STDMETHODIMP get_Encoding(VSSItemEncoding* pItemEncoding);
    STDMETHODIMP put_Encoding(VSSItemEncoding ItemEncoding);
    STDMETHODIMP get_AutoDetectEncoding(VARIANT_BOOL *pbAutoDetectEncoding);
    STDMETHODIMP put_AutoDetectEncoding(VARIANT_BOOL bAutoDetectEncoding);
    STDMETHODIMP AddWithEncoding(BSTR Local, VSSItemEncoding ItemEncoding, BSTR Comment, long iFlags, IVSSItem **ppIItem);
    STDMETHODIMP get_Physical(BSTR *pPhysical);
	STDMETHODIMP get_CRC(long *pCRC);
};

class CVSSDatabase;

//*************************************************************************************************
// Implementation of the VSSItem CoClass.  It's primary interface is IVSSItem.
//*************************************************************************************************
class CVSSItem : public IUnknown
{
friend CImpISupportErrorInfo;
friend CImpIVSSItem;

	CImpISupportErrorInfo m_ISupErrInfo;	// Required for IErrorInfo.
	CImpIVSSItem m_IVSSItem;				// Connection point container iface.

	LONG		m_cRef;						// Interface reference count.

    TFSItem     m_sItem;                    // The data about the item from TFS.
	CVSSDatabase *m_pVSSDatabase;			// Database item is from.

public:
	CVSSItem(TFSItem &sItem, CVSSDatabase *pVSSDatabase);
	~CVSSItem();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSItem::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSItem::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

	// Internal functions.
	static HRESULT NewVSSItem(TFSItem &sItem, CVSSDatabase *pVSSDatabase, IVSSItem **ppIVSSItem);
};

/* IUnknown methods implementations */
inline HRESULT CImpIVSSItem::QueryInterface(REFIID riid,LPVOID *ppvObj)
{ 
	Trace::Write("Enter CImpIVSSItem::QueryInterface");
	return m_pObj->QueryInterface(riid, ppvObj); 
}
inline ULONG CImpIVSSItem::AddRef()
{
	Trace::Write("Enter CImpIVSSItem::AddRef");
	IncIRef();
	return m_pObj->AddRef();
}
inline ULONG CImpIVSSItem::Release()
{
	Trace::Write("Enter CImpIVSSItem::Release");
	DecIRef();
	return m_pObj->Release();
}

// Forward declarations
class CEnumVersions;
class CVSSVersion;

//*************************************************************************************************
//*************************************************************************************************
class CVSSVersions : public IVSSVersions
{
friend CEnumVersions;
friend CVSSVersion;

	LONG		m_cRef;						// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CImpISupportErrorInfo m_ISupErrInfo;	// Required for IErrorInfo.

	CVSSDatabase *m_pVSSDatabase;			// Database item is from.

public:
	CVSSVersions(CVSSDatabase *pVSSDatabase);
	~CVSSVersions();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSVersions::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSVersions::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSVersions methods */
    STDMETHODIMP get_Count(long *piCount);
    STDMETHODIMP get_Item(VARIANT varVersion, IVSSVersion **ppIVersion);
    STDMETHODIMP _NewEnum(IUnknown **ppIEnum);
};

//*************************************************************************************************
//*************************************************************************************************
class CEnumVersions : public IEnumVARIANT
{
	LONG		m_cRef;						// Interface reference count.
	CImpISupportErrorInfo m_ISupErrInfo;	// Required for IErrorInfo.

	CVSSVersions *m_pVSSVersions;			// Versions collection.

public:
	CEnumVersions(CVSSVersions *pVSSVersions);
	~CEnumVersions();

	// IUnknown methods
	STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CEnumVersions::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CEnumVersions::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

	// Enumeration methods.
	STDMETHODIMP Next(ULONG iCount, VARIANT *psVar, ULONG *piFetched);
	STDMETHODIMP Skip(ULONG iCount);
	STDMETHODIMP Reset();
	STDMETHODIMP Clone(IEnumVARIANT **ppIEnum);
};

//*************************************************************************************************
//*************************************************************************************************
class CVSSVersion : public IVSSVersion
{
	LONG		m_cRef;						// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CImpISupportErrorInfo m_ISupErrInfo;	// Required for IErrorInfo.

	CVSSDatabase *m_pVSSDatabase;			// Database version is from.

public:
	CVSSVersion(CVSSDatabase *pVSSDatabase);
	~CVSSVersion();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSVersion::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSVersion::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSVersion methods */
    STDMETHODIMP get_Username(BSTR *pUsername);
    STDMETHODIMP get_VersionNumber(long *piVersion);
    STDMETHODIMP get_Action(BSTR *pAction);
    STDMETHODIMP get_Date(DATE *pDate);
    STDMETHODIMP get_Comment(BSTR *pComment);
    STDMETHODIMP get_Label(BSTR *pLabel);
    STDMETHODIMP get_VSSItem(IVSSItem **ppIItem);

    STDMETHODIMP get_LabelComment(BSTR *pComment);		
};

class CEnumVSSItems;

//*************************************************************************************************
//*************************************************************************************************
class CVSSItems : public IVSSItems
{
friend CEnumVSSItems;

	LONG		m_cRef;						// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.

	CVSSDatabase *m_pVSSDatabase;			// Database item is from.

public:
	enum ItemsTypes
	{
		Items_Links,
		Items_Children
	};

	CVSSItems(CVSSDatabase *pVSSDatabase);
	~CVSSItems();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSItems::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSItems::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSItems methods */
    STDMETHODIMP get_Count(long *piCount);
    STDMETHODIMP get_Item(VARIANT sItem, IVSSItem **ppIItem);
    STDMETHODIMP _NewEnum(IUnknown **ppIEnum);
};

//*************************************************************************************************
//*************************************************************************************************
class CEnumVSSItems : public IEnumVARIANT
{
	LONG		m_cRef;						// Interface reference count.

	CVSSItems	*m_pVSSItems;				// Collection object we're enumerating.
	int			m_iIndex;					// Current index.

public:
	CEnumVSSItems(
		CVSSItems	*pVSSItems,				// Collection object we're enumerating.
		int			iIndex = 0) :			// Index to init to.
		m_cRef(0),
		m_pVSSItems(pVSSItems),
		m_iIndex(iIndex)
	{
		Trace::Write("Enter CEnumVSSItems");
		InterlockedIncrement(&giObj);

		// Keep the collection object in scope.
		pVSSItems->AddRef();
	}
	~CEnumVSSItems()
	{
		Trace::Write("Enter ~CEnumVSSItems");
		m_pVSSItems->Release();
		InterlockedDecrement(&giObj);
	}

	// IUnknown methods
	STDMETHODIMP QueryInterface(REFIID riid,LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CEnumVSSItems::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CEnumVSSItems::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

	// Enumeration methods.
	STDMETHODIMP Next(ULONG iCount, VARIANT *psVar, ULONG *piFetched);
	STDMETHODIMP Skip(ULONG iCount);
	STDMETHODIMP Reset();
	STDMETHODIMP Clone(IEnumVARIANT **ppIEnum);
};

class CEnumVSSChkouts;

//*************************************************************************************************
//*************************************************************************************************
class CVSSChkouts : public IVSSCheckouts
{
friend CEnumVSSChkouts;

	LONG		m_cRef;						// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CVSSDatabase *m_pVSSDatabase;			// Database item is from.

public:
	CVSSChkouts(CVSSDatabase *pVSSDatabase) :
		m_cRef(0),
		m_pVSSDatabase(pVSSDatabase)
	{
		Trace::Write("Enter CVSSChkouts");
		InterlockedIncrement(&giObj);
	}
	~CVSSChkouts()
	{
		Trace::Write("Enter ~CVSSChkouts");
		InterlockedDecrement(&giObj);
	}

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSChkouts::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSChkouts::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSCheckouts methods */
    STDMETHODIMP get_Count(long *piCount);
    STDMETHODIMP get_Item(VARIANT sItem, IVSSCheckout **ppIChkouts);
    STDMETHODIMP _NewEnum(IUnknown **ppIEnum);
};

//*************************************************************************************************
//*************************************************************************************************
class CEnumVSSChkouts : public IEnumVARIANT
{
	LONG		m_cRef;						// Interface reference count.

	CVSSChkouts	*m_pVSSChkouts;				// Collection object we're enumerating.
	int			m_iIndex;					// Current index.

public:
	CEnumVSSChkouts(
		CVSSChkouts	*pVSSChkouts,			// Collection object we're enumerating.
		int			iIndex = 0) :			// Index to init to.
		m_cRef(0),
		m_pVSSChkouts(pVSSChkouts),
		m_iIndex(iIndex)
	{
		Trace::Write("Enter CEnumVSSChkouts");
		InterlockedIncrement(&giObj);

		// Keep the collection object in scope.
		pVSSChkouts->AddRef();
	}
	~CEnumVSSChkouts()
	{
		Trace::Write("Enter ~CEnumVSSChkouts");
		m_pVSSChkouts->Release();
		InterlockedDecrement(&giObj);
	}

	// IUnknown methods
	STDMETHODIMP QueryInterface(REFIID riid,LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CEnumVSSChkouts::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CEnumVSSChkouts::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

	// Enumeration methods.
	STDMETHODIMP Next(ULONG iCount, VARIANT *psVar, ULONG *piFetched);
	STDMETHODIMP Skip(ULONG iCount);
	STDMETHODIMP Reset();
	STDMETHODIMP Clone(IEnumVARIANT **ppIEnum);
};

//*************************************************************************************************
//*************************************************************************************************
class CVSSChkout : public IVSSCheckoutModifiable
{
	LONG		m_cRef;						// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CVSSDatabase *m_pVSSDatabase;			// Database item is from.

public:
	CVSSChkout(CVSSDatabase *pVSSDatabase) :// Checkout struct this is for.
		m_cRef(0),
		m_pVSSDatabase(pVSSDatabase)
	{
		Trace::Write("Enter CVSSChkout");
		InterlockedIncrement(&giObj);
	}
	~CVSSChkout()
	{
		Trace::Write("Enter ~CVSSChkout");
		InterlockedDecrement(&giObj);
	}

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSChkout::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSChkout::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSCheckout methods */
    STDMETHODIMP get_Username(BSTR *pUsername);
    STDMETHODIMP get_Date(DATE *pDate);
    STDMETHODIMP get_LocalSpec(BSTR *pLocal);
    STDMETHODIMP get_Machine(BSTR *pMachine);
    STDMETHODIMP get_Project(BSTR *pProject);
    STDMETHODIMP get_Comment(BSTR *pComment);
    STDMETHODIMP get_VersionNumber(long *piVersion);
    STDMETHODIMP get_CheckoutType(VSSCheckoutType *pType);

    /* IVSSCheckoutModifiable methods */
    STDMETHODIMP put_NewLocalSpec(BSTR Local);
    STDMETHODIMP put_NewMachine(BSTR Machine);
    STDMETHODIMP put_NewVersionNumber(long iVersion);
	STDMETHODIMP put_NewLastMerge(long iLastMerge);
};

class CVSSDatabase;

//*************************************************************************************************
//*************************************************************************************************
class CImpIVSSDatabase : public IVSSDatabase
{
	DefineIRef();							// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CVSSDatabase *m_pObj;					// Back pointer to the object.

public:
	CImpIVSSDatabase(CVSSDatabase *pObj) :
		InitIRef()
		m_pObj(pObj)
	{
		Trace::Write("Enter CImpIVSSDatabase");
	}

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid,LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSDatabase methods */
    STDMETHODIMP Open(BSTR SrcSafeIni, BSTR Username, BSTR Password);
    STDMETHODIMP get_SrcSafeIni(BSTR *pSrcSafeIni);
    STDMETHODIMP get_DatabaseName(BSTR *pDatabaseName);
    STDMETHODIMP get_UserName(BSTR *pUsername);
    STDMETHODIMP get_CurrentProject(BSTR *pPrj);
    STDMETHODIMP put_CurrentProject(BSTR Prj);
    STDMETHODIMP get_VSSItem(BSTR Spec, VARIANT_BOOL Deleted, IVSSItem **ppIVSSItem);

	STDMETHODIMP AddUser(BSTR Name, BSTR Password, VARIANT_BOOL ReadOnly, IVSSUser **ppIUser);
	STDMETHODIMP get_User(BSTR Name, IVSSUser **ppIUser);
	STDMETHODIMP get_Users(IVSSUsers **ppIUsers);
	STDMETHODIMP get_ProjectRightsEnabled(VARIANT_BOOL *pEnabled);
	STDMETHODIMP put_ProjectRightsEnabled(VARIANT_BOOL Enabled);
	STDMETHODIMP get_DefaultProjectRights(long *pRights);
	STDMETHODIMP put_DefaultProjectRights(long Rights);

    STDMETHODIMP GetSetting(BSTR Setting, BSTR *pValue);
    STDMETHODIMP Close();
	STDMETHODIMP get_ImpersonateCaller(VARIANT_BOOL *pImpersonate);
	STDMETHODIMP put_ImpersonateCaller(VARIANT_BOOL Impersonate);
};

//*************************************************************************************************
//*************************************************************************************************
class CVSSDatabase : public IUnknown
{
friend CImpISupportErrorInfo;
friend CImpIVSSDatabase;

	CImpISupportErrorInfo m_ISupErrInfo;	// Required for IErrorInfo.
	CImpIVSSDatabase m_IVSSDB;

	LONG		m_cRef;						// Interface reference count.

	BOOL		m_bLoggedIn;				// Logged in to SourceSafe?
	BSTR		m_ConnectionString;			// Connection string used to open the database.
	ITFSServer	*m_pITfs;					// Pointer to the TFS server OM object.
    BSTR        m_AuthenticatedUser;        // The user we authenticated to the server as.
    ITFSWorkspace *m_pIWorkspace;           // The TFS workspace that FPSE uses.

public:
	CVSSDatabase();
	~CVSSDatabase();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSDatabase::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSDatabase::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

	// Internal functions.
public:
	HRESULT Close();
    HRESULT GetFPSEWorkspace(ITFSWorkspace **ppIWorkspace);
    inline ITFSServer *TFSServer() 
	{ 
		Trace::Write("Enter CVSSDatabase::AuthenticatedUser");
		return m_pITfs; 
	}
    inline BSTR AuthenticatedUser() 
	{ 
		Trace::Write("Enter CVSSDatabase::AuthenticatedUser RETURN = %ls", m_AuthenticatedUser);
		return m_AuthenticatedUser; 
	}
};

/* IUnknown methods */
inline HRESULT CImpIVSSDatabase::QueryInterface(REFIID riid,LPVOID *ppvObj)
{ 
	Trace::Write("Enter CImpIVSSDatabase::QueryInterface");
	HRESULT _Return = m_pObj->QueryInterface(riid, ppvObj);
	Trace::Write("Exit  CImpIVSSDatabase::QueryInterface RETURN = %d", _Return);
	return _Return; 
}
inline ULONG CImpIVSSDatabase::AddRef()
{
//	DebugBreak();
	Trace::Write("Enter CImpIVSSDatabase::AddRef");
	IncIRef();
	ULONG _Return = m_pObj->AddRef();
	Trace::Write("Exit  CImpIVSSDatabase::AddRef RETURN = %d", _Return);
	return _Return;
}
inline ULONG CImpIVSSDatabase::Release()
{
	Trace::Write("Enter CImpIVSSDatabase::Release");
	DecIRef();
	ULONG _Return = m_pObj->Release();
	Trace::Write("Exit  CImpIVSSDatabase::Release RETURN = %d", _Return);
	return _Return;
}


class CEnumVSSUsers;

//*************************************************************************************************
//*************************************************************************************************
class CVSSUsers : public IVSSUsers
{
friend CEnumVSSUsers;

	LONG		m_cRef;						// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CVSSDatabase *m_pVSSDatabase;			// Database item is from.

public:
	CVSSUsers(CVSSDatabase *pVSSDatabase);
	~CVSSUsers();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid,LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSUsers::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSUsers::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSCheckouts methods */
    STDMETHODIMP get_Count(long *piCount);
    STDMETHODIMP get_Item(VARIANT sItem, IVSSUser **ppIUser);
    STDMETHODIMP _NewEnum(IUnknown **ppIEnum);

	// Internal functions.
	HRESULT NewInit();
};

//*************************************************************************************************
//*************************************************************************************************
class CEnumVSSUsers : public IEnumVARIANT
{
	LONG		m_cRef;						// Interface reference count.
	CVSSUsers	*m_pVSSUsers;				// Collection object we're enumerating.
	int			m_iIndex;					// Current index.

public:
	CEnumVSSUsers(
		CVSSUsers	*pVSSUsers,				// Collection object we're enumerating.
		int			iIndex = 0) :			// Index to init to.
		m_cRef(0),
		m_pVSSUsers(pVSSUsers),
		m_iIndex(iIndex)
	{
		Trace::Write("Enter CEnumVSSUsers");
		InterlockedIncrement(&giObj);

		// Keep the collection object in scope.
		pVSSUsers->AddRef();
	}
	~CEnumVSSUsers()
	{
		Trace::Write("Enter ~CEnumVSSUsers");
		m_pVSSUsers->Release();
		InterlockedDecrement(&giObj);
	}

	// IUnknown methods
	STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CEnumVSSUsers::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CEnumVSSUsers::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

	// Enumeration methods.
	STDMETHODIMP Next(ULONG iCount, VARIANT *psVar, ULONG *piFetched);
	STDMETHODIMP Skip(ULONG iCount);
	STDMETHODIMP Reset();
	STDMETHODIMP Clone(IEnumVARIANT **ppIEnum);
};

//*************************************************************************************************
//*************************************************************************************************
class CVSSUser : public IVSSUser
{
friend CImpISupportErrorInfo;

	CImpISupportErrorInfo m_ISupErrInfo;	// Required for IErrorInfo.
	LONG		m_cRef;						// Interface reference count.
	static CTypeInfo m_TI;					// Typeinfo for this interface.
	CVSSDatabase *m_pVSSDatabase;			// Database item is from.

public:
	CVSSUser(CVSSDatabase *pVSSDatabase);
	~CVSSUser();

    /* IUnknown methods */
    STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
    STDMETHODIMP_(ULONG) AddRef()
	{
		Trace::Write("Enter CVSSUser::AddRef");
		return InterlockedIncrement(&m_cRef);
	}
    STDMETHODIMP_(ULONG) Release()
	{
		Trace::Write("Enter CVSSUser::Release");
		ULONG		cRef;					// Returned reference count.

		// Delete this interface when the reference count hits 0.
		if ((cRef = InterlockedDecrement(&m_cRef)) == 0)
		{
			delete this;
		}
		return cRef;
	}

    /* IDispatch methods */
	DECLARE_AUTOMATION()

    /* IVSSUser methods */
    STDMETHODIMP Delete();
    STDMETHODIMP get_Name(BSTR *pName);
    STDMETHODIMP put_Name(BSTR Name);
    STDMETHODIMP put_Password(BSTR Password);
    STDMETHODIMP get_ReadOnly(VARIANT_BOOL *pReadOnly);
    STDMETHODIMP put_ReadOnly(VARIANT_BOOL ReadOnly);
	STDMETHODIMP get_ProjectRights(BSTR Project, long* piRights);
	STDMETHODIMP put_ProjectRights(BSTR Project, long iRights);
	STDMETHODIMP RemoveProjectRights(BSTR Project);
};

//*************************************************************************************************
// This is the class factory for VSSDatabase object.  I won't say more, because there is nothing
// special about it.
//*************************************************************************************************
class CVSSDatabaseClsFac : public IClassFactory
{
	LONG		m_cRef;						// Interface reference count.

public:
	CVSSDatabaseClsFac();
	~CVSSDatabaseClsFac();

	// IUnknown methods
	STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObj);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	// IClassFactory methods
	STDMETHODIMP CreateInstance(LPUNKNOWN pIUnkOuter, REFIID riid, LPVOID *ppvObj);
	STDMETHODIMP LockServer(BOOL bLock);
};

#endif // __SSAUTOI_H__
